package tech.heptagram.staff.cas.service.staff.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import tech.heptagram.staff.cas.common.AssertUtils;
import tech.heptagram.staff.cas.domain.info.RoleStaffSaveReq;
import tech.heptagram.staff.cas.domain.info.StaffAuthInfo;
import tech.heptagram.staff.cas.domain.po.DataAuth;
import tech.heptagram.staff.cas.domain.po.Role;
import tech.heptagram.staff.cas.domain.po.RoleStaff;
import tech.heptagram.staff.cas.mapper.CasRoleStaffMapper;
import tech.heptagram.staff.cas.service.staff.CasDataAuthService;
import tech.heptagram.staff.cas.service.staff.CasRoleService;
import tech.heptagram.staff.cas.service.staff.CasStaffService;
import tech.heptagram.staff.cas.service.staff.RoleStaffSaveCallback;
import tech.heptagram.staff.model.Staff;
import tech.heptagram.staff.query.StaffQuery;
import tech.heptagram.staff.query.StaffQueryBuilder;
import tech.heptagram.staff.service.StaffService;

/**
 * Created by yang on 2017/6/4.
 */
@Service
@Slf4j
public class CasStaffServiceImpl implements CasStaffService, ApplicationContextAware {

    private ApplicationContext applicationContext;

    private List<RoleStaffSaveCallback> callbacks = new ArrayList<>();

    @Resource
    private CasRoleStaffMapper casRoleStaffMapper;

    @Resource
    private StaffService staffService;

    @Resource
    private CasRoleService casRoleService;

    @Resource
    private CasDataAuthService casDataAuthService;

    @PostConstruct
    public void postConstruct() {
        Map<String, RoleStaffSaveCallback> callbackMap = applicationContext.getBeansOfType(RoleStaffSaveCallback.class);

        for (Map.Entry<String, RoleStaffSaveCallback> stringRoleStaffSaveCallbackEntry : callbackMap.entrySet()) {
            RoleStaffSaveCallback callback = stringRoleStaffSaveCallbackEntry.getValue();
            callbacks.add(callback);
        }
    }

    @Override
    public PageInfo<Staff> findRoleHasStaffPage(Integer roleId, Integer pageIndex, Integer pageSize) {
        PageHelper.startPage(pageIndex, pageSize);
        List<String> staffCodes = casRoleStaffMapper.selectStaffCodesByRoleId(roleId);
        PageInfo<Staff> result = new PageInfo<>();
        BeanUtils.copyProperties(staffCodes, result);

        StaffQuery staffQuery = StaffQueryBuilder.builder().staffCodes(staffCodes).build();
        List<Staff> staffs = staffService.findStaffs(staffQuery);
        result.setList(staffs);
        return result;
    }

    @Override
    @Transactional
    public Integer saveRoleStaffRelation(RoleStaffSaveReq req) {
        AssertUtils.notNull(req.getCreatedBy(), "创建人不能为空");
        AssertUtils.notNull(req.getStaffCode(), "人员编号不能为空");

        // 先清空员工的所有角色
        casRoleStaffMapper.deleteByStaffCode(req.getStaffCode(), req.getCreatedBy());

        if (!CollectionUtils.isEmpty(req.getRoles())) {
            for (Integer roleId : req.getRoles()) {
                RoleStaff roleStaff = new RoleStaff();
                roleStaff.setRoleId(roleId);
                roleStaff.setStaffCode(req.getStaffCode());
                roleStaff.setCreatedBy(req.getCreatedBy());
                roleStaff.setModifiedBy(req.getCreatedBy());

                casRoleStaffMapper.insert(roleStaff);
            }
        }

        if (null != callbacks && callbacks.size() > 0) {
            for (RoleStaffSaveCallback callback : callbacks) {
                callback.callback(req);
            }
        }
        return req.getRoles().size();
    }

    @Override
    public StaffAuthInfo findAuthByStaffCode(String staffCode) {

        StaffAuthInfo staffAuthInfo = new StaffAuthInfo();
        staffAuthInfo.setStaffCode(staffCode);

        List<Role> staffRoles = casRoleService.findRolesByStaffCode(staffCode);
        staffAuthInfo.setRoles(staffRoles);

        if(!CollectionUtils.isEmpty(staffRoles)) {
            List<Integer> roleIds = staffRoles.stream()
                .map(Role::getId)
                .collect(Collectors.toList());

            List<DataAuth> dataAuths = casDataAuthService.findByRoleIds(roleIds);
            staffAuthInfo.setDataAuths(dataAuths);
        }

        return staffAuthInfo;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 根据菜单ID查询对应角色被那些员工拥有
     *
     * @param menuId
     * @return
     */
    @Override
    public List<Staff> findByMenuId(Integer menuId) {
        List<String> staffCodes = casRoleStaffMapper.selectStaffCodesByMenuId(menuId);
        StaffQuery staffQuery = StaffQueryBuilder.builder().staffCodes(staffCodes).build();
        return staffService.findStaffs(staffQuery);
    }
}
